Skip to content

Conversation

@gturpin-dev
Copy link
Contributor

@gturpin-dev gturpin-dev commented Oct 11, 2024

This PR is a starting point of creating the make commands for the framework using the internal Generation Component.
Here's the related issue #472

It add a make:controller command

  • it take a classname as an argument like Test
  • it will suffix the class with Controller like TestController.php
  • it will prepend the main autoloaded namespace/path from the composer file to it
  • it will then glue them with a Controllers directory
  • it will generate the right namespace PSR-4 compatible
  • it support adding subfolders directly in the classname arg from the command

So, for example if I have a project with a default autoloaded namespace from composer like :
my-project/app => App
And I run make:controller Admin/Dashboard

It will generate a class named DashboardController at my-project/app/Controllers/Admin/DashboardController.php
And with the following namespace App\Controllers\Admin


Next steps before duplicate this into others make commands are :

  • Replace the way to retrieve the root path of the final user project
  • Find a way to test the file is properly generated and at the right location, with the right classname and namespace
  • Extract the main generation logic to the Generator component
  • ( later ) refactor the file creation logic by the Filesystem component
  • Handle Dummy replacements in Stubs file
  • Add MakeControllerCommand specifics params like the route path and the view path

For the 2 first TODOs I'm looking for ideas, if someone have any.

@gturpin-dev
Copy link
Contributor Author

@innocenzi For now, I'm not sure of the purpose of the ClassGenerator but I think the main logic could go there right ?

@aidan-casey
Copy link
Member

@brendt are we good moving this outside the framework to the CLI project?

Copy link
Member

@innocenzi innocenzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested this locally, but as I understand it, it will generate a controller in a predefined directory, right?

I don't really like this, personally, and I don't think it follows the philosophy of Tempest, where everything can be anywhere.

My implementation of tempest publish prompts the user every time for the path at which the file would be published. If the file already exists, the user is asked if the file should be replaced. What do you think of this approach?

@gturpin-dev
Copy link
Contributor Author

gturpin-dev commented Oct 11, 2024

I haven't tested this locally, but as I understand it, it will generate a controller in a predefined directory, right?

I don't really like this, personally, and I don't think it follows the philosophy of Tempest, where everything can be anywhere.

My implementation of tempest publish prompts the user every time for the path at which the file would be published. If the file already exists, the user is asked if the file should be replaced. What do you think of this approach?

You're right, this was the goal.

No problem for me, I can follow your already approved work, I'll check how your command work !
Then, we assume that every make command will always ask for the dist folder, we could imagine to give the main namespace path as an indication in the prompt if the user has no idea.
I'll try to go in this way ( must think about how to generate the right namespace for the file then, maybe show a select for all composer.json autoload or ? )

@brendt
Copy link
Member

brendt commented Oct 12, 2024

are we good moving this outside the framework to the CLI project?

Will discuss on Discord

@coveralls
Copy link

Pull Request Test Coverage Report for Build 11331827224

Details

  • 53 of 206 (25.73%) changed or added relevant lines in 8 files are covered.
  • 10 unchanged lines in 5 files lost coverage.
  • Overall coverage decreased (-1.4%) to 80.589%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/Tempest/Console/src/Stubs/ControllerStub.php 0 2 0.0%
src/Tempest/Support/src/PathHelper.php 29 39 74.36%
src/Tempest/Console/src/Commands/Generators/MakeControllerCommand.php 0 56 0.0%
src/Tempest/Console/src/Commands/PublishCommand.php 0 85 0.0%
Files with Coverage Reduction New Missed Lines %
src/Tempest/Generation/src/SimplifiesClassNames.php 1 90.77%
src/Tempest/Auth/src/CreatePermissionsTable.php 2 75.0%
src/Tempest/Auth/src/CreateUserPermissionTable.php 2 77.78%
src/Tempest/Auth/src/CreateUsersTable.php 2 81.82%
src/Tempest/Generation/src/ManipulatesPhpClasses.php 3 69.33%
Totals Coverage Status
Change from base Build 11319238494: -1.4%
Covered Lines: 6813
Relevant Lines: 8454

💛 - Coveralls

@gturpin-dev
Copy link
Contributor Author

Don't worry about commits, I've pulled the unmerged work of Enzo to refactor the code with its helpers on namespaces and ClassManipulator.

Then I tried to stick as much as possible to the implementation of the publish command.
So actually there is lot of duplicate code between both which is good, because it means we can now abstract those mechanism to create commands that generate files faster.
I'll look into that in the followings days.

@gturpin-dev gturpin-dev changed the title feat(generator/console): add make:controller command feat(generator/console): add make:controller command Oct 22, 2024
@gturpin-dev gturpin-dev changed the title feat(generator/console): add make:controller command feat(generator/console): add make:controller and make:model commands with the generator command attribute Oct 22, 2024
@gturpin-dev gturpin-dev changed the title feat(generator/console): add make:controller and make:model commands with the generator command attribute feat(generator/console): add make:controller, make:model commands and the generator attribute Oct 22, 2024
@gturpin-dev
Copy link
Contributor Author

As discussed in Discord here https://discord.com/channels/1236153076688359495/1295433932027990027/1298306566335893525
This PR is "ready", we are waiting to see the organization of the "roadmap" for the feature

@gturpin-dev gturpin-dev force-pushed the feat/console/generator-commands branch from 7fe30ac to 39b0ca9 Compare October 28, 2024 16:11
@gturpin-dev gturpin-dev marked this pull request as ready for review October 28, 2024 16:53
Copy link
Member

@brendt brendt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main concern is all the hoops we're jumping through to be able to return a StubFileGenerator from a command. There's a lot of complexity that comes with it, which could be avoided if we decide to rework the generator a bit, and instead inject it into the console command.

- phpstan-baseline.neon
- vendor/phpat/phpat/extension.neon
- vendor/spaze/phpstan-disallowed-calls/extension.neon
- phpstan-baseline.neon
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these changes?

"composer phpstan"
]
},
"config": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remove this? To make sure it doesn't get added again, rebase or merge main into your branch, then run composer up once more.

$consoleCommandClass,
$inputBuilder->build(),
);
$handler = ($consoleCommand instanceof GeneratorCommand)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the right way to go. I'd be very hesitant making changes within ExecuteConsoleCommand to accomodate for one specific command.

I still need to read through the rest though

$targetPath = $this->promptTargetPath($suggestedPath);
$shouldOverride = $this->askForOverride($targetPath);

return new StubFileGenerator(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about this briefly on Discord: I'm not convinced yet that we need a special kind of console commands that return a special kind of class. I rather just inject the generator into the console command.

Take, for example, a look at how the install command works: it doesn't need to return anything special, but rather passes the responsibility of actually installing a package to the underlying Installer class.


final class MakeModelCommand
{
use HasGeneratorCommand;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This trait should be renamed to IsGeneratorCommand

$this->assertMatchesSnapshot($class->print());
}

#[Test]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the removal?

* The values are the replacements for the placeholders (e.g. 'App\Models')
* @param bool $shouldOverride Whether the generator should override the file if it already exists.
*/
public function __construct(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why this data is injected into the constructor instead of being passed to the generate method? Tempest tries to have all classes injectable, and aims to have a clear separation of data and functionality. When I see a "Stub File Generator", my assumption is that it's a class that I can inject and reuse, while its generate method would require me to pass in context-specific data.

Something like this:

$this->stubGenerator->generate($stub, $target, $replacements, $shouldOverwrite);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because atm the generator isn't a service but something like a DTO and the generate method is expected to be run once.
The instance is created and returned by the GeneratorCommand method handler.
In case, if we decide to change the overall approch this could be changed as you mention I guess 😄

return $this->reflectionClass->getName();
}

public function getFilePath(): string|false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change this to string. It'll only return false if we're reflecting over internal PHP classes. I'd rather throw an exception in that case:

$path = $this->reflectionClass->getFileName();

if ($path === false)
{
    // throw
}

return $path;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check this out because I don't remember tweaking on this, so maybe a vestige of the feat/publish


public function __construct(
private PHPReflector|PHPReflectionType|string $reflector,
private PHPReflector|PHPReflectionType|string|null $reflector,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity: when does this happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happen to me weeks ago but if I remember correctly, an instance of the TypeReflector were created dynamically and something null passed in param so it throws an exception.
But giving "null" works.


final readonly class PathHelper
{
public static function root(string ...$paths): string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this one anymore. Use root_path() instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, i'll correct this ASAP

@brendt
Copy link
Member

brendt commented Oct 31, 2024

Let's close this one in favor of #647

@brendt brendt closed this Oct 31, 2024
@gturpin-dev gturpin-dev deleted the feat/console/generator-commands branch November 12, 2024 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants